package com.ahwei.common.rest.handler;


import com.ahwei.common.rest.base.R;
import com.ahwei.common.rest.base.ResultCode;
import com.ahwei.common.rest.exception.ApplicationException;
import com.ahwei.common.rest.exception.ResourceNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Set;

/**
 * @Author：ahWei Email: ahwei163@qq.com
 * Date: 2022-04-15 20:12:04
 * Description: 这是一个Java文件！
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionControllerAdvice {

    /**
     * GET请求中@Valid验证参数失败后抛出异常BindException
     * GET请求中@RequestBody参数校验失败后抛出异常MethodArgumentNotValidException
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
    public R<String> handlerBindException(BindException e) {
        StringBuilder messages = new StringBuilder(1024);
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError error : fieldErrors) {
            messages.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("\n\r");
        }
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        //请求参数校验错误
        return R.error(ResultCode.PARAM_VALID_ERROR, messages.toString());
    }

    /*
     * GET请求中@RequestBody参数校验失败后抛出异常MethodArgumentNotValidException
     * @param e ·
     * @return ·
     */
   /* @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public R<String> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        StringBuilder messages = new StringBuilder(1024);
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError error : fieldErrors) {
            messages.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("\n\r");
        }
        return R.error(ResultCode.PARAM_VALID_ERROR,messages.toString());
    }*/


    /**
     * ·@RequestParam参数校验失败后抛出异常ConstraintViolationException
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public R<String> handlerMethodArgumentNotValidException(ConstraintViolationException e) {
        StringBuilder messages = new StringBuilder(1024);
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        for (ConstraintViolation<?> error : constraintViolations) {
            messages.append(error.getPropertyPath().toString()).append(": ").append(error.getMessage()).append("\n\r");
        }
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        return R.error(ResultCode.PARAM_VALID_ERROR, messages.toString());
    }


    /**
     * 不支持的请求方法
     *
     * @param ex ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<String> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        //return R.error(ResultCode.METHOD_NOT_SUPPORTED);
        log.error("\r\n[Exception INFO]==> |" + ex.getMessage());
        return R.error(ResultCode.METHOD_NOT_SUPPORTED);
    }


    /**
     * 不支持的媒体类型
     *
     * @param ex ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public R<MediaType> httpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException ex) {
        log.error("\r\n[Exception INFO]==> |" + ex.getMessage());
        return R.error(ResultCode.MEDIA_TYPE_NOT_SUPPORTED, ex.getContentType());
    }

    /**
     * 处理资源未发现异常ResourceNotFoundException
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(ResourceNotFoundException.class)
    public R<String> handleResourceNotFoundException(ResourceNotFoundException e) {
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        return R.error(ResultCode.NOT_FOUND, e.getMessage());
    }

    /**
     * 没有发现资源 404
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public R<String> handleNoHandlerFoundException(NoHandlerFoundException e) {
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        return R.error(ResultCode.NOT_FOUND, e.getMessage());
    }


    /**
     * 处理自定义异常ApplicationException
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(ApplicationException.class)
    public R<String> applicationExceptionHandler(ApplicationException e) {
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        // 异常中指定的错误代码，消息按优先级合并在异常的message中
        return R.error(e.getResultCode(), e.getMessage());
    }

    /**
     * 访问拒绝处理、无权限
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(AccessDeniedException.class)
    public R<String> handleAccessDeniedException(AccessDeniedException e) {
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        return R.error(ResultCode.LOGIN_ACL, "没有访问权限!");
    }

    /**
     * 处理空指针异常NullPointerException
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(NullPointerException.class)
    public R<String> nullPointerExceptionHandler(NullPointerException e) {
        // 异常中指定的错误代码，消息按优先级合并在异常的message中
        log.error("\r\n[Exception INFO]==> |" + e.toString());

        return R.error(ResultCode.UNKNOWN, e.getMessage());
    }

    /**
     * 通常在最后的方法处理最大的Exception，保证兜底
     *
     * @param e ·
     * @return ·
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    public R<String> exceptionHandler(Exception e) {
        log.error("\r\n[Exception INFO]==> |" + e.getMessage());
        return R.error(ResultCode.UNKNOWN, e.getMessage());
    }
}
